package com.gvjn.ant.customtasks.spring;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import com.gvjn.ant.customtasks.commons.Parser;
import com.gvjn.ant.customtasks.commons.RandomUniqueStrings;

public class ProcessFiles {

	static List mapFileObfuscatedPackage1 = null;
	static List mapFileObfuscatedPackageValues1 = null;
	static List mapFileObfuscatedPackage2 = null;
	static List mapFileObfuscatedPackageValues2 = null;
	static List springBeanValues = null;
	static List springBeanValuesModified = null;
	static List servletValues = null;
	static List servletValuesModified = null;
	static String packagePrefix1 = "org.apache.jsp.";
	static String packagePrefix2 = "com.";

	static String beanPrefix1 = "id=\"";
	static String beanSuffix1 = "\" ";
	static String beanPrefix2 = "bean=\"";
	static String beanSuffix2 = "\" ";

	static String servletPrefix = "<servlet-name>";
	static String servletSuffix = "</servlet-name>";

	static String mapFile = "";
	static String inputWebXML = "";
	static String inputSpringXML = "";
	static String outputWebXML = "";
	static String outputSpringXML = "";

	static boolean removeComments = false;
	static boolean removeEmptyLines = false;
	static boolean removeLineBreaks = false;
	static boolean removeWhitespaces = false;

	public static boolean init(String inWebXML, String outWebXML, String inSpringXML, String outSpringXML, String mapFile,
			String removeCommentsTxt, String removeEmptyLinesTxt, String removeLineBreaksTxt, String removeWhitespacesTxt){
		ProcessFiles.inputWebXML = inWebXML;
		ProcessFiles.outputWebXML = outWebXML;
		ProcessFiles.inputSpringXML = inSpringXML;
		ProcessFiles.outputSpringXML = outSpringXML;
		ProcessFiles.mapFile = mapFile;

		ProcessFiles.removeComments = Boolean.parseBoolean(removeCommentsTxt);
		ProcessFiles.removeEmptyLines = Boolean.parseBoolean(removeEmptyLinesTxt);
		ProcessFiles.removeLineBreaks = Boolean.parseBoolean(removeLineBreaksTxt);
		ProcessFiles.removeWhitespaces = Boolean.parseBoolean(removeWhitespacesTxt);

		return readFiles();
	}

	private static boolean readFiles() {
		File mapFileObject = new File(mapFile);
		File webXMLFileObject = new File(inputWebXML);
		File springXMLFileObject = new File(inputSpringXML);

		try {
			BufferedReader inputMapFileForFile1 = new BufferedReader(new FileReader(mapFileObject));
			BufferedReader inputMapFileForFile2 = new BufferedReader(new FileReader(mapFileObject));
			BufferedReader inputSpringXMLFile = new BufferedReader(new FileReader(springXMLFileObject));
			BufferedReader inputWebXMLFile = new BufferedReader(new FileReader(webXMLFileObject));
			BufferedReader inputWebXMLFileForOutput = new BufferedReader(new FileReader(webXMLFileObject));
			BufferedReader inputSpringXMLFileForOutput = new BufferedReader(new FileReader(springXMLFileObject));

			//===================================================================
			//Reading file for package data for web.xml
			//===================================================================
			try {
				String line = "";
				int tagStart = -1, tagEnd = -1;
				mapFileObfuscatedPackage1 = new ArrayList();
				mapFileObfuscatedPackageValues1 = new ArrayList();
				while ((line = inputMapFileForFile1.readLine()) != null) {
					String stringStart = packagePrefix1, stringEnd = ":";
					tagStart = line.toLowerCase().indexOf(stringStart.toLowerCase());
					tagEnd = line.toLowerCase().indexOf(stringEnd.toLowerCase(),tagStart);
					//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
					if((tagStart != -1) && (tagEnd != -1)){
						String tagElement = (line.subSequence(tagStart + stringStart.length(),tagEnd)).toString();

						List elements = Parser.parseMyListWithDelim(tagElement, " -> ");
						mapFileObfuscatedPackage1.add(packagePrefix1 + elements.get(0));
						mapFileObfuscatedPackageValues1.add(elements.get(1));

						//System.out.print(packagePrefix + elements.get(0));
						//System.out.println(" ### Value: " + elements.get(1));
					}

					tagStart = -1;
					tagEnd = -1;
				}
			} finally {
				inputMapFileForFile1.close();
			}


			//===================================================================
			//Reading file for package data for spring-servlet.xml
			//===================================================================
			try {
				String line = "";
				int tagStart = -1, tagEnd = -1;
				mapFileObfuscatedPackage2 = new ArrayList();
				mapFileObfuscatedPackageValues2 = new ArrayList();
				while ((line = inputMapFileForFile2.readLine()) != null) {
					String stringStart = packagePrefix2, stringEnd = ":";
					tagStart = line.toLowerCase().indexOf(stringStart.toLowerCase());
					tagEnd = line.toLowerCase().indexOf(stringEnd.toLowerCase(),tagStart);
					//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
					if((tagStart != -1) && (tagEnd != -1)){
						String tagElement = (line.subSequence(tagStart + stringStart.length(),tagEnd)).toString();

						List elements = Parser.parseMyListWithDelim(tagElement, " -> ");
						mapFileObfuscatedPackage2.add(packagePrefix2 + elements.get(0));
						mapFileObfuscatedPackageValues2.add(elements.get(1));

						//System.out.print(packagePrefix + elements.get(0));
						//System.out.println(" ### Value: " + elements.get(1));
					}

					tagStart = -1;
					tagEnd = -1;
				}
			} finally {
				inputMapFileForFile2.close();
			}

			//===================================================================
			//Reading file for spring bean data for spring-servlet.xml
			//===================================================================
			try {
				String line = ""; long lineNumber = 0;
				int tagStart = -1, tagEnd = -1;
				springBeanValues = new ArrayList();
				springBeanValuesModified = new ArrayList();
				while ((line = inputSpringXMLFile.readLine()) != null) {
					lineNumber++;
					if(line.contains("<!-- gxSTART -->")){
						//System.out.println("gxSTART#" + lineNumber);

						while ((line = inputSpringXMLFile.readLine()) != null) {
							lineNumber++;
							if(line.contains("<!-- gxEND -->")){
								//System.out.println("gxEND#" + lineNumber);
								break;
							}

							tagStart = line.toLowerCase().indexOf(beanPrefix1.toLowerCase());
							tagEnd = line.toLowerCase().indexOf(beanSuffix1.toLowerCase(),tagStart);
							//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
							if((tagStart != -1) && (tagEnd != -1)){
								String tagElement = (line.subSequence(tagStart + beanPrefix1.length(),tagEnd)).toString();
								springBeanValues.add(tagElement);

								//System.out.println(tagElement);
								//System.out.println(" ### Value: " + elements.get(1));
							}

							tagStart = -1;
							tagEnd = -1;
						}
					}else{
						continue;
					}
				}

				springBeanValuesModified = RandomUniqueStrings.generate(springBeanValues.size(),"O");
				System.out.println("Total beans found: " + springBeanValues.size() + ", Total random strings generated: " + springBeanValuesModified.size());
			} finally {
				inputSpringXMLFile.close();
			}

			//===================================================================
			//Reading file for servlets data for web.xml
			//===================================================================
			try {
				String line = ""; long lineNumber = 0;
				int tagStart = -1, tagEnd = -1;
				servletValues = new ArrayList();
				servletValuesModified = new ArrayList();
				while ((line = inputWebXMLFile.readLine()) != null) {
					lineNumber++;
					if(line.toLowerCase().contains(("<!-- JSPC servlet mappings start -->").toLowerCase())){
						//System.out.println("JSPC-START#" + lineNumber);

						while ((line = inputWebXMLFile.readLine()) != null) {
							lineNumber++;
							if(line.toLowerCase().contains(("<!-- JSPC servlet mappings end -->").toLowerCase())){
								//System.out.println("JSPC-END#" + lineNumber);
								break;
							}

							tagStart = line.toLowerCase().indexOf(servletPrefix.toLowerCase());
							tagEnd = line.toLowerCase().indexOf(servletSuffix.toLowerCase(),tagStart);
							//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
							if((tagStart != -1) && (tagEnd != -1)){
								String tagElement = (line.subSequence(tagStart + servletPrefix.length(),tagEnd)).toString();
								servletValues.add(tagElement);

								//System.out.println(tagElement);
								//System.out.println(" ### Value: " + elements.get(1));
							}

							tagStart = -1;
							tagEnd = -1;
						}
					}else{
						continue;
					}
				}

				servletValues = RandomUniqueStrings.checkDuplicates(servletValues);
				servletValuesModified = RandomUniqueStrings.generate(servletValues.size(),"O8");
				System.out.println("Total servlets found: " + servletValues.size() + ", Total random strings generated: " + servletValuesModified.size());
			} finally {
				inputWebXMLFile.close();
			}

			//===================================================================
			//Writing output - modified web.xml
			//===================================================================
			File newWebXMLFile = new File(outputWebXML);
			FileWriter fw = new FileWriter(newWebXMLFile);
			StringBuilder outputString1 = new StringBuilder();

			try {
				String line = "";
				int tagStart = -1, tagEnd = -1;
				while ((line = inputWebXMLFileForOutput.readLine()) != null) {
					String stringStart = packagePrefix1, stringEnd = "</servlet-class>";
					tagStart = line.toLowerCase().indexOf(stringStart.toLowerCase());
					tagEnd = line.toLowerCase().indexOf(stringEnd.toLowerCase(),tagStart);
					//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
					if((tagStart != -1) && (tagEnd != -1)){
						String tagElement = packagePrefix1 + (line.subSequence(tagStart + stringStart.length(),tagEnd)).toString();
						//System.out.println("tagElement: " + tagElement);
						for(int i=0 ; i<mapFileObfuscatedPackage1.size() ; i++){
							if(((String)mapFileObfuscatedPackage1.get(i)).equalsIgnoreCase(tagElement)){
								line = line.replaceAll(tagElement, (String)mapFileObfuscatedPackageValues1.get(i));
								break;
							}
						}
					}

					tagStart = -1;
					tagEnd = -1;

					for(int z=0 ; z<servletValues.size() ; z++){
						if( line.contains(servletPrefix + (String)servletValues.get(z) + servletSuffix) ){
							line = line.replaceAll((servletPrefix + (String)servletValues.get(z) + servletSuffix),(servletPrefix + (String)servletValuesModified.get(z) + servletSuffix));
						}
					}

					if(removeComments){
						String commentStart = "<!-- ", commentEnd = " -->";
						int idx1 = line.toLowerCase().indexOf(commentStart.toLowerCase());
						int idx2 = line.toLowerCase().indexOf(commentEnd.toLowerCase(),tagStart);
						if((idx1 != -1) && (idx2 != -1)){
							String commentTagElement = (line.subSequence(idx1 + commentStart.length(),idx2)).toString();
							line = line.replaceAll((commentStart+commentTagElement+commentEnd),"");
						}
					}

					if(removeWhitespaces) line = line.trim();

					if(removeEmptyLines){
						if(line.trim().length() != 0){
							outputString1.append(line);
							if(!removeLineBreaks) outputString1.append(System.getProperty("line.separator"));
						}
					}
					else{
						outputString1.append(line);
						if(!removeLineBreaks) outputString1.append(System.getProperty("line.separator"));
					}
				}

			    Writer writer = new BufferedWriter(fw);
				try {
					writer.write(outputString1.toString()); // FileWriter always assumes default encoding is OK!
				} finally {
					writer.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			} finally {
				inputWebXMLFileForOutput.close();
			}

			//===================================================================
			//Writing output - modified spring-servlet.xml
			//===================================================================
			File newSpringServletFile = new File(outputSpringXML);
			fw = new FileWriter(newSpringServletFile);
			StringBuilder outputString2 = new StringBuilder();

			try {
				String line = "";
				int tagStart = -1, tagEnd = -1;
				while ((line = inputSpringXMLFileForOutput.readLine()) != null) {
					String stringStart = packagePrefix2, stringEnd = "\"";
					tagStart = line.toLowerCase().indexOf(stringStart.toLowerCase());
					tagEnd = line.toLowerCase().indexOf(stringEnd.toLowerCase(),tagStart);
					//System.out.println("tagStart: " + tagStart + " ## tagEnd: " + tagEnd);
					if((tagStart != -1) && (tagEnd != -1)){
						String tagElement = packagePrefix2 + (line.subSequence(tagStart + stringStart.length(),tagEnd)).toString();
						//System.out.println("tagElement: " + tagElement);
						for(int i=0 ; i<mapFileObfuscatedPackage2.size() ; i++){
							if(((String)mapFileObfuscatedPackage2.get(i)).equalsIgnoreCase(tagElement)){
								line = line.replaceAll(tagElement, (String)mapFileObfuscatedPackageValues2.get(i));
								break;
							}
						}

					}

					tagStart = -1;
					tagEnd = -1;

					for(int z=0 ; z<springBeanValues.size() ; z++){
						if( line.contains(beanPrefix1 + (String)springBeanValues.get(z) + beanSuffix1) ){
							line = line.replaceAll((beanPrefix1 + (String)springBeanValues.get(z) + beanSuffix1),(beanPrefix1 + (String)springBeanValuesModified.get(z) + beanSuffix1));
						}
						if( line.contains(beanPrefix2 + (String)springBeanValues.get(z) + beanSuffix2) ){
							line = line.replaceAll((beanPrefix2 + (String)springBeanValues.get(z) + beanSuffix2),(beanPrefix2 + (String)springBeanValuesModified.get(z) + beanSuffix2));
						}
					}

					if(removeComments){
						String commentStart = "<!-- ", commentEnd = " -->";
						int idx1 = line.toLowerCase().indexOf(commentStart.toLowerCase());
						int idx2 = line.toLowerCase().indexOf(commentEnd.toLowerCase(),tagStart);
						if((idx1 != -1) && (idx2 != -1)){
							String commentTagElement = (line.subSequence(idx1 + commentStart.length(),idx2)).toString();
							line = line.replaceAll((commentStart+commentTagElement+commentEnd),"");
						}
					}

					if(removeWhitespaces) line = line.trim();

					if(removeEmptyLines){
						if(line.trim().length() != 0){
							outputString2.append(line);
							if(!removeLineBreaks) outputString2.append(System.getProperty("line.separator"));
						}
					}
					else{
						outputString2.append(line);
						if(!removeLineBreaks) outputString2.append(System.getProperty("line.separator"));
					}
				}

			    Writer writer = new BufferedWriter(fw);
				try {
					writer.write(outputString2.toString()); // FileWriter always assumes default encoding is OK!
				} finally {
					writer.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			} finally {
				inputSpringXMLFileForOutput.close();
			}

			//==========================================================================================
			//==========================================================================================
			//==========================================================================================

			return true;

		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
}